package cz.proks.easyhelpdesk.gwt;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

import cz.proks.easyhelpdesk.api.model.Category;
import cz.proks.easyhelpdesk.api.model.Filter;
import cz.proks.easyhelpdesk.api.model.Helpdesk;
import cz.proks.easyhelpdesk.api.model.HelpdeskMember;
import cz.proks.easyhelpdesk.api.model.HelpdeskRole;
import cz.proks.easyhelpdesk.api.model.Thread;
import cz.proks.easyhelpdesk.api.model.ThreadMember;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.api.model.base.AnIdentifiableModel;

public class Globals {            
    private static Globals INSTANCE = new Globals(); 
        
    private User user;
    private HelpdeskMember helpdeskMember;
    private Helpdesk helpdesk;
    private Map<Long, Helpdesk> helpdesks;
    private Map<Helpdesk, Map<Long, HelpdeskMember>> helpdeskHelpdeskMembers;
    private Map<HelpdeskMember, User> helpdeskMemberUser;
    private Map<HelpdeskMember, Map<Long, ThreadMember>> helpdeskMemberThreadMembers;
    private Map<ThreadMember, Thread> threadMemberThread;    
    private Map<Helpdesk, Map<Long, Filter>> helpdeskFilters;
    private Map<Helpdesk, Map<Long, Category>> helpdeskCategories;    
    private Map<Helpdesk, Collection<HelpdeskRole>> helpdeskRoles;
    
    private Globals() {        
        this.user = null;
        this.helpdeskMember = null;
        this.helpdesk = null;
        this.helpdesks = new LinkedHashMap<Long, Helpdesk>();
        this.helpdeskHelpdeskMembers = new LinkedHashMap<Helpdesk, Map<Long, HelpdeskMember>>();
        this.helpdeskMemberUser = new LinkedHashMap<HelpdeskMember, User>();
        this.helpdeskMemberThreadMembers = new LinkedHashMap<HelpdeskMember, Map<Long,ThreadMember>>();
        this.threadMemberThread = new LinkedHashMap<ThreadMember, Thread>();        
        this.helpdeskFilters = new LinkedHashMap<Helpdesk, Map<Long, Filter>>();
        this.helpdeskCategories = new LinkedHashMap<Helpdesk, Map<Long, Category>>();   
        this.helpdeskRoles = new LinkedHashMap<Helpdesk, Collection<HelpdeskRole>>();        
    }    
    
    public static User getCurrentUser() {               
        return INSTANCE.user;
    }
    
    public static void setCurrentUser(User user) {
        INSTANCE.user = user;        
    }
    
    public static HelpdeskMember getCurrentHelpdeskMember() {
        return INSTANCE.helpdeskMember;
    }
    
    public static void setCurrentHelpdeskMember(HelpdeskMember helpdeskMember) {
        INSTANCE.helpdeskMember = helpdeskMember;
    }
    
    public static Helpdesk getCurrentHelpdesk() {
        return INSTANCE.helpdesk;
    }
    
    public static void setCurrentHelpdesk(Helpdesk helpdesk) {
        INSTANCE.helpdesk = getHelpdesk(helpdesk != null ? helpdesk.getId() : null);
    }
    
    public static Helpdesk getHelpdesk(Long id) {
        return INSTANCE.helpdesks.get(id);        
    }
    
    public static Collection<Helpdesk> getHelpdesks() {            
        return INSTANCE.helpdesks.values();
    }
    
    public static void setHelpdesks(Collection<Helpdesk> helpdesks) {
        INSTANCE.helpdesks.clear();
        
        if (helpdesks != null)
            for (Helpdesk helpdesk : helpdesks)
                INSTANCE.helpdesks.put(helpdesk.getId(), helpdesk);                    
    }
    
    public static void addHelpdesk(Helpdesk helpdesk) {        
        INSTANCE.helpdesks.put(helpdesk.getId(), helpdesk);          
        
        if (getCurrentHelpdesk() == null)
            setCurrentHelpdesk(helpdesk);
    }
    
    public static void removeHelpdesk(Helpdesk helpdesk) {        
        INSTANCE.helpdesks.remove(helpdesk);
        
        if (getCurrentHelpdesk().equals(helpdesk))
            setCurrentHelpdesk(null);
    }
    
    public static Collection<Helpdesk> getHelpdesksForAmin() {
        Collection<Helpdesk> helpdesks = new LinkedList<Helpdesk>();
        
        for (Helpdesk helpdesk : getHelpdesks())
            if (isHelpdeskOwner(getCurrentUser(), helpdesk))
                helpdesks.add(helpdesk);
        
        return helpdesks;
    }
    
    public static Map<Long, HelpdeskMember> getHelpdeskMemberMapFor(Helpdesk helpdesk) {
        if (helpdesk == null)
            return null;
        
        if (!INSTANCE.helpdeskHelpdeskMembers.containsKey(helpdesk))
            INSTANCE.helpdeskHelpdeskMembers.put(helpdesk, new LinkedHashMap<Long, HelpdeskMember>());
        
        return INSTANCE.helpdeskHelpdeskMembers.get(helpdesk);
    }
    
    public static void setHelpdeskMemberMapFor(Helpdesk helpdesk, Map<Long, HelpdeskMember> helpdeskMemberMap) {
        Map<Long, HelpdeskMember> map = getHelpdeskMemberMapFor(helpdesk);
        
        map.clear();
        
        if (helpdeskMemberMap != null)
            map.putAll(helpdeskMemberMap);
    }
    
    public static HelpdeskMember getHelpdeskMemberFor(Helpdesk helpdesk, User user) {
        return getHelpdeskMemberFor(helpdesk, user.getId());
    }
    
    public static HelpdeskMember getHelpdeskMemberFor(Helpdesk helpdesk, Long userId) {
        Map<Long, HelpdeskMember> map = getHelpdeskMemberMapFor(helpdesk);
        
        for (HelpdeskMember helpdeskMember : map.values())
            if (helpdeskMember.getUserId().equals(userId))
                return helpdeskMember;
        
        return null;
    }
    
    public static User getUserFor(HelpdeskMember helpdeskMember) {
        if (helpdeskMember == null)
            return null;
        
        return INSTANCE.helpdeskMemberUser.get(helpdeskMember);
    }
    
    public static void setUserFor(HelpdeskMember helpdeskMember, User user) {
        INSTANCE.helpdeskMemberUser.put(helpdeskMember, user);
    }        
    
    public static Map<Long, ThreadMember> getThreadMemberMapFor(HelpdeskMember helpdeskMember) {
        if (helpdeskMember == null)
            return null;
        
        if (!INSTANCE.helpdeskMemberThreadMembers.containsKey(helpdeskMember))
            INSTANCE.helpdeskMemberThreadMembers.put(helpdeskMember, new LinkedHashMap<Long, ThreadMember>());
        
        return INSTANCE.helpdeskMemberThreadMembers.get(helpdeskMember);
    }
    
    public static void setThreadMemberMapFor(HelpdeskMember helpdeskMember, Map<Long, ThreadMember> threadMemberMap) {
        Map<Long, ThreadMember> map = getThreadMemberMapFor(helpdeskMember);
        
        map.clear();
        
        if (threadMemberMap != null)
            map.putAll(threadMemberMap);
    }
             
    public static Thread getThreadFor(ThreadMember threadMember) {
        if (threadMember == null)
            return null;
                        
        return INSTANCE.threadMemberThread.get(threadMember);
    }
    
    public static void setThreadFor(ThreadMember threadMember, Thread thread) {
        INSTANCE.threadMemberThread.put(threadMember, thread);
    }
    
    public static Map<Long, Filter> getFilterMapFor(Helpdesk helpdesk) {
        if (helpdesk == null)
            return null;
        
        if (!INSTANCE.helpdeskFilters.containsKey(helpdesk))
            INSTANCE.helpdeskFilters.put(helpdesk, new LinkedHashMap<Long, Filter>());
        
        return INSTANCE.helpdeskFilters.get(helpdesk);
    }
    
    public static void setFilterMapFor(Helpdesk helpdesk, Map<Long, Filter> filterMap) {
        Map<Long, Filter> map = getFilterMapFor(helpdesk);
        
        map.clear();
        
        if (filterMap != null)
            map.putAll(filterMap);
    }
    
    public static Map<Long, Category> getCategoryMapFor(Helpdesk helpdesk) {
        if (helpdesk == null)
            return null;
        
        if (!INSTANCE.helpdeskCategories.containsKey(helpdesk))
            INSTANCE.helpdeskCategories.put(helpdesk, new LinkedHashMap<Long, Category>());
        
        return INSTANCE.helpdeskCategories.get(helpdesk);
    }
    
    public static void setCategoryMapFor(Helpdesk helpdesk, Map<Long, Category> categoryMap) {
        Map<Long, Category> map = getCategoryMapFor(helpdesk);
        
        map.clear();
        
        if (categoryMap != null)
            map.putAll(categoryMap);
    }
    
    public static Collection<HelpdeskRole> getHelpdeskRolesFor(Helpdesk helpdesk) {
        if (helpdesk == null)
            return null;
        
        if (!INSTANCE.helpdeskRoles.containsKey(helpdesk))
            INSTANCE.helpdeskRoles.put(helpdesk, new LinkedList<HelpdeskRole>());
        
        return INSTANCE.helpdeskRoles.get(helpdesk);       
    }
    
    public static void setHelpdeskRolesFor(Helpdesk helpdesk, Collection<HelpdeskRole> helpdeskRoles) {
        Collection<HelpdeskRole> collection = getHelpdeskRolesFor(helpdesk);
        
        collection.clear();
        
        if (helpdeskRoles != null)
            collection.addAll(helpdeskRoles);
    }
    
    public static void clear() {
        INSTANCE = new Globals();
    }        
    
    public static <Domain extends AnIdentifiableModel> Map<Long, Domain> asMap(Collection<Domain> collection) {
        Map<Long, Domain> map = new LinkedHashMap<Long, Domain>();
        
        if (collection != null)
            for (Domain domain : collection)
                map.put(domain.getId(), domain);
        
        return map;
    }
    
    public static <Domain extends AnIdentifiableModel> Collection<Domain> asCollection(Map<Long, Domain> map) {
        return map != null ? map.values() : new LinkedList<Domain>();
    }
    
    public static boolean isHelpdeskOwner() {
        return isHelpdeskOwner(getCurrentUser(), getCurrentHelpdesk());
    }
    
    public static boolean isHelpdeskOwner(User user, Helpdesk helpdesk) {
        return helpdesk == null || user == null ? false : helpdesk.getOwnerId().equals(user.getId());
    }
}
